//46_手写Promise.js

//有什么作用？ -- 解决回调地狱问题

// 1.结构初始化---使用类
// 2.this指向---注意！
// 3.then实现---在类上添加一个then方法
// 4.执行异常---使用tryCatch捕获并返回一个拒绝的Promise对象
// 5.异步---使用setTimeout模拟
// 6.回调保存---使用数组将每次then中的回调保存，放在最后执行
// 7.链式调用---在then中返回一个新的Promise对象

class MyPromise{

    static P = '待定'
    static F = '解决'
    static R = '拒绝'

    constructor(func){
        this.status = MyPromise.P //初始化状态为待定
        this.value = null//保存解决和拒绝的值
        this.resArr = []//保存每次then内部解决的回调函数-回调保存
        this.rejArr = []//保存每次then内部拒绝的回调函数-回调保存
        try {
            func(this.res.bind(this),this.rej.bind(this))//使用bind改变this指向是有必要的
        } catch (error) {
            this.rej(error)//如果MyPromise内部有异常则返回拒绝的MyPromise对象
        }
    }

    res(value){
        setTimeout(()=>{//将res内部代码放在最后执行-回调保存
            if(this.status === MyPromise.P){
                this.status = MyPromise.F
                this.value = value
                this.resArr.forEach(fn=>{//-回调保存
                    fn(value)
                })
            }
        })
    }
    rej(value){
        setTimeout(()=>{//将rej内部代码放在最后执行-回调保存
            if(this.status === MyPromise.P){
                this.status = MyPromise.R
                this.value = value
                this.rejArr.forEach(fn=>{//-回调保存
                    fn(value)
                })
            }
        })
    }

    then(onRes,onRej){
        return new MyPromise((res,rej)=>{//返回一个新的MyPromise对象---实现链式调用
            onRes = typeof onRes === 'function' ?onRes:value=>value//如果不是函数则将其置为一个空函数
            onRej = typeof onRej === 'function' ?onRej:err=>{throw err}//如果不是函数则将其置为一个空函数
    
            if(this.status === MyPromise.P){//如果状态为待定，则将回调保存，因为状态会异步更改-回调保存
                this.resArr.push(onRes)
                this.rejArr.push(onRej)
            }
            if(this.status === MyPromise.F){
                setTimeout(()=>{//then为异步，使用定时器将其与同步区分开
                    try {
                        onRes(this.value)
                    } catch (error) {
                        rej(error)//如果有异常则返回拒绝的MyPromise对象
                    }
                })
            }
            if(this.status === MyPromise.R){
                setTimeout(()=>{
                    try {
                        onRej(this.value)
                    } catch (error) {
                        rej(error)//如果有异常则返回拒绝的MyPromise对象
                    }
                })
            }
        })
    }

    catch(fn){
        return this.then(null,fn)
    }
}

//resolve方法
MyPromise.resolve = function(val){
    return new Promise((resolve,reject)=>{
        resolve(val)
    });
}
//reject方法
MyPromise.reject = function(val){
    return new Promise((resolve,reject)=>{
        reject(val)
    });
}
//race方法 
Promise.race = function(promises){
    return new Promise((resolve,reject)=>{
        for(let i=0;i<promises.length;i++){
        promises[i].then(resolve,reject)
        };
    })
}
//all方法(获取所有的promise，都执行then，把结果放到数组，一起返回)
Promise.all = function(promises){
    let arr = [];
    let i = 0;
    function processData(index,data){
        arr[index] = data;
        i++;
        if(i == promises.length){
        resolve(arr);
        };
    };
    return new Promise((resolve,reject)=>{
        for(let i=0;i<promises.length;i++){
        promises[i].then(data=>{
            processData(i,data);
        },reject);
        };
    });
}


//测试
console.log('同步-1')
let p = new MyPromise((res,rej)=>{
    console.log('初始化')
    setTimeout(() => {
        res('解决！')
        rej('拒绝！')//无效
    }, 1000);
})
console.log('同步-2')
p.then(
    (res)=>{console.log(res)},
    (err)=>{console.log(err)}
).then(
    (res)=>{console.log(res);},
    (err)=>{console.log(err)}
).catch(
    (err)=>{console.log(err)}
)
console.log('同步-3')

// 同步-1
// 初始化
// 同步-2
// 同步-3
// 解决！

MyPromise.resolve('Promise.resolve---解决！').then((res)=>{console.log(res)},(err)=>{console.log(err)})
MyPromise.reject('Promise.reject---拒绝！').then((res)=>{console.log(res)},(err)=>{console.log(err)})

// Promise.resolve---解决！
// Promise.reject---拒绝！